package pl.plesken.graphic;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.imageio.ImageIO;

import com.jhlabs.image.PerspectiveFilter;


public class GraphicTools {

	public BufferedImage loadImage(String ImageFile) {
		BufferedImage image = null;
		try {
			image = ImageIO.read(new File(ImageFile));
		} catch(IOException e) {
			e.printStackTrace();
		}
		return image;
	}
	
    public BufferedImage loadImageURL(URL url) {
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(url);
        } catch (Exception ignore) {
            bi = null;
        }
        return bi;
    }

	public void saveImageAsPng(BufferedImage image, String output) {
		try {
			ImageIO.write(image, "png", new File(output));
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

	public void saveImageAsJpg(BufferedImage image, String output) {
		try {
			BufferedImage bufImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            bufImage.createGraphics().drawImage(image, 0, 0, null, null);
            
			ImageIO.write(bufImage, "jpg", new File(output));
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	public BufferedImage resizeImage(BufferedImage image, int width, int height) {
		Image newImage = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
		
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        bi.getGraphics().drawImage(newImage, 0, 0, null);
        return bi;
	}
	
    public BufferedImage createReflectedPicture(BufferedImage avatar, String reflectionHeight) {
        int avatarWidth = avatar.getWidth();
        int avatarHeight = avatar.getHeight();
             
        BufferedImage gradient = createGradientMask(avatarWidth, avatarHeight, Float.valueOf(reflectionHeight));
        BufferedImage buffer = createReflection(avatar, avatarWidth, avatarHeight, Float.valueOf(reflectionHeight));

        applyAlphaMask(gradient, buffer, avatarWidth, avatarHeight);

        return buffer;
    }
	
    public static BufferedImage createGradientMask(int avatarWidth, int avatarHeight, float reflectionHeight) {
        BufferedImage gradient = new BufferedImage(avatarWidth, avatarHeight, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        Graphics2D g = gradient.createGraphics();
       
        float reflectionStart, reflectionEnd, opacityStart, opacityEnd;
        float reflectionHeightAbsolute = avatarHeight * (reflectionHeight / 100);

        reflectionStart = (0 / 100) * reflectionHeightAbsolute;
        reflectionEnd   = (100 / 100) * reflectionHeightAbsolute;
                opacityStart    = 30 / 100;
                opacityEnd      = 100 / 100;

        GradientPaint painter = new GradientPaint(0.0f, reflectionStart, new Color(1.0f, 1.0f, 1.0f, opacityStart), 0.0f, reflectionEnd, new Color(1.0f, 1.0f, 1.0f, opacityEnd));
        g.setPaint(painter);
        g.fill(new Rectangle2D.Double(0, 0, avatarWidth, avatarHeight));

        g.dispose();
        gradient.flush();

        return gradient;
    }
    
    public static void applyAlphaMask(BufferedImage gradient, BufferedImage buffer, int avatarWidth, int avatarHeight) {
        Graphics2D g2 = buffer.createGraphics();
        g2.setComposite(AlphaComposite.DstOut);
        g2.drawImage(gradient, null, 0, avatarHeight);
        g2.dispose();
    }
    
    public static BufferedImage createReflection(BufferedImage avatar, int avatarWidth, int avatarHeight, float reflectionHeight) {
        // Increase the height of the image to cater for the reflection.
        int newHeight = (int) (avatarHeight * (1 + (reflectionHeight / 100) ));
 
        BufferedImage buffer = new BufferedImage(avatarWidth, newHeight, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        Graphics2D g = buffer.createGraphics();

        g.drawImage(avatar, null, null);
        g.translate(0, (avatarHeight << 1) + 2);

        AffineTransform reflectTransform = AffineTransform.getScaleInstance(1.0, -1.0);
        g.drawImage(avatar, reflectTransform, null);
        g.translate(0, -(avatarHeight << 1));

        g.dispose();

        return buffer;
    }
    
	public BufferedImage create3DPicture(BufferedImage bi, String perspectiveDirection, float perspectiveTop, float perspectiveBottom) {
		   
		   int w = bi.getWidth();
		   int h = bi.getHeight();
		       
		   int Top3d = (int) (h * perspectiveTop / 100);
		   int Bot3d = (int) (h * perspectiveBottom / 100);
		       
		   PerspectiveFilter perspectiveFilter = new PerspectiveFilter();
		      // Top Left (x/y), Top Right (x/y), Bottom Right (x/y), Bottom Left (x/y)
		       
		  if (perspectiveDirection.equalsIgnoreCase("right")) {
			   perspectiveFilter.setCorners(0, 0, w, Top3d, w, h - Bot3d, 0, h);
		   } else {
		       perspectiveFilter.setCorners(0, Top3d, w, 0, w, h, 0, h - Bot3d);
		   }
		   return perspectiveFilter.filter(bi, null);
	}
	
    public BufferedImage drawLogoHD(String skinHome, BufferedImage bi, Boolean addOtherLogo, String movieType) {
    	if (movieType.toUpperCase().contains("HD") || movieType.toUpperCase().contains("BLU")) {
    		try {
    			InputStream in = new FileInputStream(skinHome + File.separator + "resources" + File.separator + "hd.png");
    			BufferedImage biHd = ImageIO.read(in);
    			Graphics g = bi.getGraphics();

    			/*if (addOtherLogo && (movieType.toUpperCase().contains("TV"))) {
    				// Both logos are required, so put the HD logo on the LEFT
    				g.drawImage(biHd, 5, bi.getHeight() - biHd.getHeight() - 5, null);
    			} else {*/
    				// Only the HD logo is required so set it in the centre
    				g.drawImage(biHd, bi.getWidth() / 2 - biHd.getWidth() / 2, bi.getHeight() - biHd.getHeight() - 5, null);
    			//}

    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
        return bi;
    }
	
    public BufferedImage drawLogoTV(String skinHome, BufferedImage bi, Boolean addOtherLogo, String movieType) {
    	if (movieType.toUpperCase().contains("HD") || movieType.toUpperCase().contains("BLU")) {
    		try {
                InputStream in = new FileInputStream(skinHome + File.separator + "resources" + File.separator + "tv.png");
                BufferedImage biTV = ImageIO.read(in);
                Graphics g = bi.getGraphics();

                if (addOtherLogo && movieType.toUpperCase().contains("HD")) {
                    // Both logos are required, so put the TV logo on the RIGHT
                    g.drawImage(biTV, bi.getWidth() - biTV.getWidth() - 5, bi.getHeight() - biTV.getHeight() - 5, null);
                } else {
                    // Only the TV logo is required so set it in the centre
                    g.drawImage(biTV, bi.getWidth() / 2 - biTV.getWidth() / 2, bi.getHeight() - biTV.getHeight() - 5, null);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
    	}
        return bi;
    }

/*    private BufferedImage drawLanguage(String skinHome, Movie movie, BufferedImage bi) {
        String lang = movie.getLanguage();
        if (lang != null && !lang.isEmpty() && !lang.equalsIgnoreCase("Unknown")) {

            try {
                InputStream in = new FileInputStream(skinHome + File.separator + "resources" + File.separator + "languages" + File.separator + lang + ".png");
                BufferedImage biLang = ImageIO.read(in);
                Graphics g = bi.getGraphics();
                g.drawImage(biLang, 2, 2, null);
            } catch (IOException e) {
                logger.warning("Failed drawing Language logo to poster file: Please check that language specific graphic (" + lang + ".png) is in the resources/languages directory.");
            }
        }

        return bi;
    }*/

    
    public BufferedImage addImage(BufferedImage image, BufferedImage addImage) {
   		Graphics g = addImage.getGraphics();
   		
   		g.drawImage(image, addImage.getWidth()/2 - image.getWidth()/2 + 10, addImage.getHeight()/2 - image.getHeight()/2, null);   		
    	
    	return addImage;   	
    }
  
    public BufferedImage addHDLogo(BufferedImage image, BufferedImage addLogoImage) {
   		Graphics g = image.getGraphics();
   		
   		g.drawImage(addLogoImage, image.getWidth()/2 - addLogoImage.getWidth()/2 + 130, image.getHeight()/2 - addLogoImage.getHeight()/2 + 190, null);   		
    	
    	return image;   	
    }
    
    public BufferedImage addStars(BufferedImage image, BufferedImage stars) {
   		Graphics g = image.getGraphics();
   		
   		g.drawImage(stars, image.getWidth()/2 - stars.getWidth()/2 + 117, image.getHeight()/2 - stars.getHeight()/2 - 229, null);   		
    	
    	return image;   	
    }
    
    public BufferedImage addTVLogo(BufferedImage image, BufferedImage addTVImage) {
   		Graphics g = image.getGraphics();
   		
   		//for tv_show_under.png
   		//g.drawImage(addTVImage, image.getWidth()/2 - addTVImage.getWidth()/2 - 95, image.getHeight() - addTVImage.getHeight() + 24, null);   		
   		g.drawImage(addTVImage, image.getWidth()/2 - addTVImage.getWidth()/2 - 112, image.getHeight() - addTVImage.getHeight(), null);
   		
    	return image;   	
    }
    
    public BufferedImage coverImage(BufferedImage image, BufferedImage coverImage) {
   		Graphics g = image.getGraphics();
   		
   		g.drawImage(coverImage, 1, 1, null);   		
    	
    	return image;   	
    }
  
    public BufferedImage addSetImage(BufferedImage image, BufferedImage addImage, int width, int height) {
   		Graphics g = addImage.getGraphics();
   		
   		g.drawImage(image, width, height, null);   		
    	
    	return addImage;   	
    }
    
    public BufferedImage addFormat(BufferedImage image, BufferedImage format) {
   		Graphics g = image.getGraphics();
   		
   		g.drawImage(format, image.getWidth()/2 - format.getWidth()/2 - 117, image.getHeight()/2 - format.getHeight()/2 - 227, null);   		
    	
    	return image;   	
    }
    
    public BufferedImage createMask(int maskWidth, int maskHeight) {
        BufferedImage mask = new BufferedImage(maskWidth, maskHeight, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        Graphics2D g = mask.createGraphics();
       
        float reflectionStart, reflectionEnd, opacityStart, opacityEnd;

        reflectionStart = 0;
        reflectionEnd   = 0;
        opacityStart    = 0;
        opacityEnd      = 0;

        GradientPaint painter = new GradientPaint(0.0f, reflectionStart, new Color(1.0f, 1.0f, 1.0f, opacityStart), 0.0f, reflectionEnd, new Color(1.0f, 1.0f, 1.0f, opacityEnd));
        g.setPaint(painter);
        g.fill(new Rectangle2D.Double(0, 0, maskWidth, maskHeight));

        g.dispose();
        mask.flush();

        return mask;
    }
    
    public BufferedImage resize(BufferedImage img, int newW, int newH) {  
        int w = img.getWidth();  
        int h = img.getHeight();
        
        BufferedImage dimg;
        
        if (img.getType() == 0) {
        	dimg = new BufferedImage(newW, newH, 7);
        } else {
        	dimg = new BufferedImage(newW, newH, img.getType());
        }
        
        Graphics2D g = dimg.createGraphics();  
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);  
        g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);  
        g.dispose();  
        return dimg;  
    }  
}
